library(tidyverse)
Registered S3 method overwritten by 'dplyr':
  method         from       
  print.location geojsonlint
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ---------------------------------------------------------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.1.0     v dplyr   1.0.5
v tidyr   1.1.3     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
-- Conflicts ------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(readxl)

# Working with Spatial Data
library(sf)
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(rmapshaper)

# Embedding HTML Widgets
library(htmltools)
library(leaflet)

Import daily covid cases and deaths for the UK from the Public Health England coronavirus data api.

uk_daily_covid19_cases <- read_csv("https://api.coronavirus.data.gov.uk/v2/data?areaType=utla&metric=newCasesByPublishDate&format=csv")

-- Column specification ---------------------------------------------------------------------------------------------------------------------
cols(
  areaCode = col_character(),
  areaName = col_character(),
  areaType = col_character(),
  date = col_date(format = ""),
  newCasesByPublishDate = col_double()
)

uk_daily_covid19_deaths <- read_csv("https://api.coronavirus.data.gov.uk/v2/data?areaType=utla&metric=newOnsDeathsByRegistrationDate&format=csv")

-- Column specification ---------------------------------------------------------------------------------------------------------------------
cols(
  areaCode = col_character(),
  areaName = col_character(),
  areaType = col_character(),
  date = col_date(format = ""),
  newOnsDeathsByRegistrationDate = col_double()
)
glimpse(uk_daily_covid19_cases)
Rows: 90,887
Columns: 5
$ areaCode              <chr> "E06000003", "E06000014", "E06000050", "E08000001", "E08000016", "E08000031", "E08000032", "E09000018", "E090~
$ areaName              <chr> "Redcar and Cleveland", "York", "Cheshire West and Chester", "Bolton", "Barnsley", "Wolverhampton", "Bradford~
$ areaType              <chr> "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla~
$ date                  <date> 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, 2021-07-12, ~
$ newCasesByPublishDate <dbl> 189, 130, 194, 143, 287, 120, 362, 107, 223, 106, 315, 5, 103, 35, 54, 220, 111, 134, 114, 182, 92, 300, 87, ~
glimpse(uk_daily_covid19_deaths)
Rows: 11,313
Columns: 5
$ areaCode                       <chr> "E06000003", "E06000014", "E06000050", "E08000001", "E08000016", "E08000031", "E08000032", "E0900001~
$ areaName                       <chr> "Redcar and Cleveland", "York", "Cheshire West and Chester", "Bolton", "Barnsley", "Wolverhampton", ~
$ areaType                       <chr> "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utla", "utl~
$ date                           <date> 2021-06-25, 2021-06-25, 2021-06-25, 2021-06-25, 2021-06-25, 2021-06-25, 2021-06-25, 2021-06-25, 202~
$ newOnsDeathsByRegistrationDate <dbl> 0, 0, 1, 7, 0, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 0, 3, 1, 1, 3, 0, 4, 0~
uk_daily_covid19_deaths %>%
  select(areaCode) %>%
  unique() %>%
  filter(str_detect(areaCode, "^E")) %>%
  nrow()
[1] 149
Eng_daily_covid19_indicators <- uk_daily_covid19_cases %>%
  full_join(uk_daily_covid19_deaths) %>% 
  filter(str_detect(areaCode, "^E")) %>%
  replace_na(list(newOnsDeathsByRegistrationDate = 0,
                  newCasesByPublishDate = 0))
Joining, by = c("areaCode", "areaName", "areaType", "date")
  

Daily Cases

Data has 90887 rows and 5 columns.

Dates: 2020-04-17 to 2021-07-12.

It assigns covid cases by the date the data was first included in published totals, not when the initial test was taken.

The data is at Upper Tier Local Authority level, of which 149 are in England.

Daily Deaths

Data has 11313 rows and 5 columns.

Dates: 2020-03-13 to 2021-06-25.

It assigns deaths to covid if COVID-19 is mentioned as a cause on the death certificate, while the date refers to the date the death was registered.

The data is at Upper Tier Local Authority level, of which 149 are in England.


mid_year_population_2020 <- read_excel("data/ukpopestimatesmid2020on2020geography.xlsx",
                                       sheet = "MYE4",
                                       skip = 7) %>%
  select("areaCode" = Code, "areaName" = Name, Geography, "populationMid2020" = `Mid-2020`) %>%
  filter(str_detect(areaCode, "^E")) %>% 
  filter(Geography %in% c("Unitary Authority", "Metropolitan District", "County", "London Borough"))

utla_rural_classification <- read_excel("data/utla_ruc.xlsx",
                                       skip = 2) %>%
  rename("areaCode" = `UTLA19 CD`,
         "areaName" = `UTLA19 NM`,
         "detailedRuralClassification" = RUC11,
         "broadRuralClassification" = `Broad RUC11`)

utla_data <- mid_year_population_2020 %>%
  left_join(utla_rural_classification) %>%
  replace_na(list(detailedRuralClassification = "Urban with Significant Rural",
                  broadRuralClassification = "Urban with Significant Rural")) %>%
  mutate(areaName = str_replace(areaName, "City of London", "Hackney and City of London") %>%
           str_replace(., "Hackney$", "Hackney and City of London") %>%
           str_replace(., "Isles of Scilly", "Cornwall and Isles of Scilly") %>%
           str_replace(., "Cornwall$", "Cornwall and Isles of Scilly"),
         areaCode = str_replace(areaCode, "E09000001", "E09000012"),
         areaCode = str_replace(areaCode, "E06000053", "E06000052"),
         areaCode = str_replace(areaCode, "E06000060", "E10000002")) %>%
  group_by(areaCode, areaName, Geography, detailedRuralClassification, broadRuralClassification) %>%
  summarise(populationMid2020 = sum(populationMid2020)) %>%
  ungroup()
Joining, by = c("areaCode", "areaName")
`summarise()` has grouped output by 'areaCode', 'areaName', 'Geography', 'detailedRuralClassification'. You can override using the `.groups` argument.
glimpse(utla_data)
Rows: 149
Columns: 6
$ areaCode                    <chr> "E06000001", "E06000002", "E06000003", "E06000004", "E06000005", "E06000006", "E06000007", "E06000008",~
$ areaName                    <chr> "Hartlepool", "Middlesbrough", "Redcar and Cleveland", "Stockton-on-Tees", "Darlington", "Halton", "War~
$ Geography                   <chr> "Unitary Authority", "Unitary Authority", "Unitary Authority", "Unitary Authority", "Unitary Authority"~
$ detailedRuralClassification <chr> "Urban with City and Town", "Urban with City and Town", "Urban with Significant Rural", "Urban with Cit~
$ broadRuralClassification    <chr> "Predominantly Urban", "Predominantly Urban", "Urban with Significant Rural", "Predominantly Urban", "P~
$ populationMid2020           <dbl> 93836, 141285, 137228, 197419, 107402, 129759, 209397, 150030, 138381, 259126, 343201, 159364, 172748, ~
  

In order to compare the data between local authorities, we must normalise the data for population level, as a local authority with a higher population would naturally accumulate more covid cases and deaths, ceterus-paribus.

I have imported the rural urban classification for upper tier local authorities, which is constructed using the same method as the local authority district rural urban classification. Areas with a rural population over 50% are classified as predominantly rural, and areas with a rural population below 25% are classified as predominantly urban.


detailed_ruc_order <- c("Mainly Rural", "Largely Rural", "Urban with Significant Rural", "Urban with City and Town", "Urban with Minor Conurbation", "Urban with Major Conurbation")

overall_data <- Eng_daily_covid19_indicators %>%
  left_join(utla_data) %>%
  group_by(detailedRuralClassification) %>%
  summarise(TotalCases = sum(newCasesByPublishDate),
            TotalDeaths = sum(newOnsDeathsByRegistrationDate),
            nLAD = n_distinct(areaCode)) %>%
  mutate(detailedRuralClassification = factor(detailedRuralClassification, detailed_ruc_order)) %>%
  arrange(detailedRuralClassification) %>%
  left_join(utla_data %>% 
              group_by(detailedRuralClassification) %>%
              summarise(pop2020 = sum(populationMid2020),
                        nLADcheck = n_distinct(areaCode))) %>%
  ungroup() %>%
  mutate(OverallCaseRate = TotalCases/pop2020*100000,
         OverallDeathRate = TotalDeaths/pop2020*100000)
Joining, by = c("areaCode", "areaName")
Joining, by = "detailedRuralClassification"
  
# overall_data %>%
#   ggplot(aes(OverallCaseRate, detailedRuralClassification)) +
#   geom_col() 

A clear pattern in the overall rates of covid cases when each local authority is aggregated by rural classification.

The overall case rate for the most rural areas is 3647 cases per 100,000 population, while the overall case rate for the most urban areas is 9357 cases per 100,000 population.

The covid rate of the most urban areas is 2.6 times the covid rate in the most rural areas.

However, the overall death rate had less clear pattern. The most rural areas had the a rate of 124 deaths registered per 100,000 population, while the overall death rate for the most urban areas had the 3rd highest death rate of 240 deaths registered per 100,000 population. The highest death rate came from Urban areas with Minor Conurbations with a death rate of 263 deaths registered per 100,000 population.


UTLA_shp <- st_read("spatial data/COunties_and_Unitary_Authorities_(December_2019)_Boundaries_UK_BFC.shp") %>%
  rmapshaper::ms_simplify()
Reading layer `Counties_and_Unitary_Authorities_(December_2019)_Boundaries_UK_BFC' from data source `C:\Users\spoic\OneDrive\Documents\R\Projects\Data-Science-Graduate-Scheme\spatial data\Counties_and_Unitary_Authorities_(December_2019)_Boundaries_UK_BFC.shp' using driver `ESRI Shapefile'
Simple feature collection with 216 features and 10 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -116.1928 ymin: 5337.901 xmax: 655653.8 ymax: 1220302
projected CRS:  OSGB 1936 / British National Grid
UTLA_cases_deaths <- Eng_daily_covid19_indicators %>%
  group_by(areaCode, areaName) %>%
  summarise(TotalCases = sum(newCasesByPublishDate),
            TotalDeaths = sum(newOnsDeathsByRegistrationDate),
            nLAD = n_distinct(areaCode)) %>%
  left_join(utla_data) %>%
  ungroup() %>%
  mutate(OverallCaseRate = TotalCases/populationMid2020*100000,
         OverallDeathRate = TotalDeaths/populationMid2020*100000)
`summarise()` has grouped output by 'areaCode'. You can override using the `.groups` argument.
Joining, by = c("areaCode", "areaName")
UTLA_ruc_shp <- left_join(UTLA_shp, UTLA_cases_deaths, by = c("ctyua19cd" = "areaCode")) %>%
  st_transform(4326) %>% # Convert from a UK Projection (epsg = 27700) to a Global Projection (epsg = 4326)
  mutate(OverallCaseRate_comma = scales::comma(OverallCaseRate, accuracy = 1),
         OverallDeathRate_comma = scales::comma(OverallDeathRate, accuracy = 1))
  # select(lad11cd, lad11nm, ruc11, broad_ruc11, st_areasha)
bins <- c(0, 1000, 2000, 4000, 6000, 8000, 10000, Inf)
There were 18 warnings (use warnings() to see them)
pal <- colorBin("YlOrRd", domain = UTLA_ruc_shp$OverallCaseRate, bins = bins)

labels <- sprintf(
  "<strong>%s</strong><br/>%s<strong><br/>%s",
  UTLA_ruc_shp$areaName, UTLA_ruc_shp$OverallCaseRate_comma, UTLA_ruc_shp$detailedRuralClassification
) %>% lapply(htmltools::HTML)

UTLA_ruc_shp %>%
  leaflet() %>%
  addTiles() %>%
  addPolygons(
    stroke = T, 
    smoothFactor = 1, 
    fillOpacity = 0.7,
    fillColor = ~pal(OverallCaseRate),
    color = "white",
    weight = 2,
    dashArray = "1",
    highlight = highlightOptions(
      weight = 5,
      color = "#666",
      dashArray = "",
      fillOpacity = 0.7,
      bringToFront = TRUE),
  label = labels,
  labelOptions = labelOptions(
    style = list("font-weight" = "normal", padding = "3px 8px"),
    textsize = "15px",
    direction = "auto"))
LS0tDQp0aXRsZTogIkRvZXMgcnVyYWxpdHkgaGF2ZSBhbiBpbXBhY3Qgb24gdGhlIHNwcmVhZCBvZiBDb3JvbmF2aXJ1cz8iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkeGwpDQoNCiMgV29ya2luZyB3aXRoIFNwYXRpYWwgRGF0YQ0KbGlicmFyeShzZikNCmxpYnJhcnkocm1hcHNoYXBlcikNCg0KIyBFbWJlZGRpbmcgSFRNTCBXaWRnZXRzDQpsaWJyYXJ5KGh0bWx0b29scykNCmxpYnJhcnkobGVhZmxldCkNCg0KYGBgDQoNCkltcG9ydCBkYWlseSBjb3ZpZCBjYXNlcyBhbmQgZGVhdGhzIGZvciB0aGUgVUsgZnJvbSB0aGUgUHVibGljIEhlYWx0aCBFbmdsYW5kIGNvcm9uYXZpcnVzIGRhdGEgYXBpLg0KDQpgYGB7cn0NCg0KdWtfZGFpbHlfY292aWQxOV9jYXNlcyA8LSByZWFkX2NzdigiaHR0cHM6Ly9hcGkuY29yb25hdmlydXMuZGF0YS5nb3YudWsvdjIvZGF0YT9hcmVhVHlwZT11dGxhJm1ldHJpYz1uZXdDYXNlc0J5UHVibGlzaERhdGUmZm9ybWF0PWNzdiIpDQoNCnVrX2RhaWx5X2NvdmlkMTlfZGVhdGhzIDwtIHJlYWRfY3N2KCJodHRwczovL2FwaS5jb3JvbmF2aXJ1cy5kYXRhLmdvdi51ay92Mi9kYXRhP2FyZWFUeXBlPXV0bGEmbWV0cmljPW5ld09uc0RlYXRoc0J5UmVnaXN0cmF0aW9uRGF0ZSZmb3JtYXQ9Y3N2IikNCg0KYGBgDQoNCmBgYHtyfQ0KZ2xpbXBzZSh1a19kYWlseV9jb3ZpZDE5X2Nhc2VzKQ0KDQpnbGltcHNlKHVrX2RhaWx5X2NvdmlkMTlfZGVhdGhzKQ0KDQp1a19kYWlseV9jb3ZpZDE5X2RlYXRocyAlPiUNCiAgc2VsZWN0KGFyZWFDb2RlKSAlPiUNCiAgdW5pcXVlKCkgJT4lDQogIGZpbHRlcihzdHJfZGV0ZWN0KGFyZWFDb2RlLCAiXkUiKSkgJT4lDQogIG5yb3coKQ0KDQpFbmdfZGFpbHlfY292aWQxOV9pbmRpY2F0b3JzIDwtIHVrX2RhaWx5X2NvdmlkMTlfY2FzZXMgJT4lDQogIGZ1bGxfam9pbih1a19kYWlseV9jb3ZpZDE5X2RlYXRocykgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChhcmVhQ29kZSwgIl5FIikpICU+JQ0KICByZXBsYWNlX25hKGxpc3QobmV3T25zRGVhdGhzQnlSZWdpc3RyYXRpb25EYXRlID0gMCwNCiAgICAgICAgICAgICAgICAgIG5ld0Nhc2VzQnlQdWJsaXNoRGF0ZSA9IDApKQ0KICANCg0KYGBgDQoNCiMjIyBEYWlseSBDYXNlcw0KDQpEYXRhIGhhcyBgciBucm93KHVrX2RhaWx5X2NvdmlkMTlfY2FzZXMpYCByb3dzIGFuZCBgciBuY29sKHVrX2RhaWx5X2NvdmlkMTlfY2FzZXMpYCBjb2x1bW5zLg0KDQpEYXRlczogYHIgbWluKHVrX2RhaWx5X2NvdmlkMTlfY2FzZXMkZGF0ZSlgIHRvIGByIG1heCh1a19kYWlseV9jb3ZpZDE5X2Nhc2VzJGRhdGUpYC4NCg0KSXQgYXNzaWducyBjb3ZpZCBjYXNlcyBieSB0aGUgZGF0ZSB0aGUgZGF0YSB3YXMgZmlyc3QgaW5jbHVkZWQgaW4gcHVibGlzaGVkIHRvdGFscywgbm90IHdoZW4gdGhlIGluaXRpYWwgdGVzdCB3YXMgdGFrZW4uDQoNClRoZSBkYXRhIGlzIGF0IFVwcGVyIFRpZXIgTG9jYWwgQXV0aG9yaXR5IGxldmVsLCBvZiB3aGljaCAxNDkgYXJlIGluIEVuZ2xhbmQuDQoNCiMjIyBEYWlseSBEZWF0aHMNCg0KRGF0YSBoYXMgYHIgbnJvdyh1a19kYWlseV9jb3ZpZDE5X2RlYXRocylgIHJvd3MgYW5kIGByIG5jb2wodWtfZGFpbHlfY292aWQxOV9kZWF0aHMpYCBjb2x1bW5zLg0KDQpEYXRlczogYHIgbWluKHVrX2RhaWx5X2NvdmlkMTlfZGVhdGhzJGRhdGUpYCB0byBgciBtYXgodWtfZGFpbHlfY292aWQxOV9kZWF0aHMkZGF0ZSlgLg0KDQpJdCBhc3NpZ25zIGRlYXRocyB0byBjb3ZpZCBpZiBDT1ZJRC0xOSBpcyBtZW50aW9uZWQgYXMgYSBjYXVzZSBvbiB0aGUgZGVhdGggY2VydGlmaWNhdGUsIHdoaWxlIHRoZSBkYXRlIHJlZmVycyB0byB0aGUgZGF0ZSB0aGUgZGVhdGggd2FzIHJlZ2lzdGVyZWQuDQoNClRoZSBkYXRhIGlzIGF0IFVwcGVyIFRpZXIgTG9jYWwgQXV0aG9yaXR5IGxldmVsLCBvZiB3aGljaCAxNDkgYXJlIGluIEVuZ2xhbmQuDQoNCmBgYHtyIE90aGVyLURhdGFzZXRzfQ0KDQptaWRfeWVhcl9wb3B1bGF0aW9uXzIwMjAgPC0gcmVhZF9leGNlbCgiZGF0YS91a3BvcGVzdGltYXRlc21pZDIwMjBvbjIwMjBnZW9ncmFwaHkueGxzeCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJNWUU0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSA3KSAlPiUNCiAgc2VsZWN0KCJhcmVhQ29kZSIgPSBDb2RlLCAiYXJlYU5hbWUiID0gTmFtZSwgR2VvZ3JhcGh5LCAicG9wdWxhdGlvbk1pZDIwMjAiID0gYE1pZC0yMDIwYCkgJT4lDQogIGZpbHRlcihzdHJfZGV0ZWN0KGFyZWFDb2RlLCAiXkUiKSkgJT4lIA0KICBmaWx0ZXIoR2VvZ3JhcGh5ICVpbiUgYygiVW5pdGFyeSBBdXRob3JpdHkiLCAiTWV0cm9wb2xpdGFuIERpc3RyaWN0IiwgIkNvdW50eSIsICJMb25kb24gQm9yb3VnaCIpKQ0KDQp1dGxhX3J1cmFsX2NsYXNzaWZpY2F0aW9uIDwtIHJlYWRfZXhjZWwoImRhdGEvdXRsYV9ydWMueGxzeCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBza2lwID0gMikgJT4lDQogIHJlbmFtZSgiYXJlYUNvZGUiID0gYFVUTEExOSBDRGAsDQogICAgICAgICAiYXJlYU5hbWUiID0gYFVUTEExOSBOTWAsDQogICAgICAgICAiZGV0YWlsZWRSdXJhbENsYXNzaWZpY2F0aW9uIiA9IFJVQzExLA0KICAgICAgICAgImJyb2FkUnVyYWxDbGFzc2lmaWNhdGlvbiIgPSBgQnJvYWQgUlVDMTFgKQ0KDQp1dGxhX2RhdGEgPC0gbWlkX3llYXJfcG9wdWxhdGlvbl8yMDIwICU+JQ0KICBsZWZ0X2pvaW4odXRsYV9ydXJhbF9jbGFzc2lmaWNhdGlvbikgJT4lDQogIHJlcGxhY2VfbmEobGlzdChkZXRhaWxlZFJ1cmFsQ2xhc3NpZmljYXRpb24gPSAiVXJiYW4gd2l0aCBTaWduaWZpY2FudCBSdXJhbCIsDQogICAgICAgICAgICAgICAgICBicm9hZFJ1cmFsQ2xhc3NpZmljYXRpb24gPSAiVXJiYW4gd2l0aCBTaWduaWZpY2FudCBSdXJhbCIpKSAlPiUNCiAgbXV0YXRlKGFyZWFOYW1lID0gc3RyX3JlcGxhY2UoYXJlYU5hbWUsICJDaXR5IG9mIExvbmRvbiIsICJIYWNrbmV5IGFuZCBDaXR5IG9mIExvbmRvbiIpICU+JQ0KICAgICAgICAgICBzdHJfcmVwbGFjZSguLCAiSGFja25leSQiLCAiSGFja25leSBhbmQgQ2l0eSBvZiBMb25kb24iKSAlPiUNCiAgICAgICAgICAgc3RyX3JlcGxhY2UoLiwgIklzbGVzIG9mIFNjaWxseSIsICJDb3Jud2FsbCBhbmQgSXNsZXMgb2YgU2NpbGx5IikgJT4lDQogICAgICAgICAgIHN0cl9yZXBsYWNlKC4sICJDb3Jud2FsbCQiLCAiQ29ybndhbGwgYW5kIElzbGVzIG9mIFNjaWxseSIpLA0KICAgICAgICAgYXJlYUNvZGUgPSBzdHJfcmVwbGFjZShhcmVhQ29kZSwgIkUwOTAwMDAwMSIsICJFMDkwMDAwMTIiKSwNCiAgICAgICAgIGFyZWFDb2RlID0gc3RyX3JlcGxhY2UoYXJlYUNvZGUsICJFMDYwMDAwNTMiLCAiRTA2MDAwMDUyIiksDQogICAgICAgICBhcmVhQ29kZSA9IHN0cl9yZXBsYWNlKGFyZWFDb2RlLCAiRTA2MDAwMDYwIiwgIkUxMDAwMDAwMiIpKSAlPiUNCiAgZ3JvdXBfYnkoYXJlYUNvZGUsIGFyZWFOYW1lLCBHZW9ncmFwaHksIGRldGFpbGVkUnVyYWxDbGFzc2lmaWNhdGlvbiwgYnJvYWRSdXJhbENsYXNzaWZpY2F0aW9uKSAlPiUNCiAgc3VtbWFyaXNlKHBvcHVsYXRpb25NaWQyMDIwID0gc3VtKHBvcHVsYXRpb25NaWQyMDIwKSkgJT4lDQogIHVuZ3JvdXAoKQ0KDQpnbGltcHNlKHV0bGFfZGF0YSkNCiAgDQpgYGANCg0KSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgZGF0YSBiZXR3ZWVuIGxvY2FsIGF1dGhvcml0aWVzLCB3ZSBtdXN0IG5vcm1hbGlzZSB0aGUgZGF0YSBmb3IgcG9wdWxhdGlvbiBsZXZlbCwgYXMgYSBsb2NhbCBhdXRob3JpdHkgd2l0aCBhIGhpZ2hlciBwb3B1bGF0aW9uIHdvdWxkIG5hdHVyYWxseSBhY2N1bXVsYXRlIG1vcmUgY292aWQgY2FzZXMgYW5kIGRlYXRocywgY2V0ZXJ1cy1wYXJpYnVzLg0KDQpJIGhhdmUgaW1wb3J0ZWQgdGhlIHJ1cmFsIHVyYmFuIGNsYXNzaWZpY2F0aW9uIGZvciB1cHBlciB0aWVyIGxvY2FsIGF1dGhvcml0aWVzLCB3aGljaCBpcyBjb25zdHJ1Y3RlZCB1c2luZyB0aGUgc2FtZSBtZXRob2QgYXMgdGhlIGxvY2FsIGF1dGhvcml0eSBkaXN0cmljdCBydXJhbCB1cmJhbiBjbGFzc2lmaWNhdGlvbi4gQXJlYXMgd2l0aCBhIHJ1cmFsIHBvcHVsYXRpb24gb3ZlciA1MCUgYXJlIGNsYXNzaWZpZWQgYXMgcHJlZG9taW5hbnRseSBydXJhbCwgYW5kIGFyZWFzIHdpdGggYSBydXJhbCBwb3B1bGF0aW9uIGJlbG93IDI1JSBhcmUgY2xhc3NpZmllZCBhcyBwcmVkb21pbmFudGx5IHVyYmFuLg0KDQpgYGB7cn0NCg0KZGV0YWlsZWRfcnVjX29yZGVyIDwtIGMoIk1haW5seSBSdXJhbCIsICJMYXJnZWx5IFJ1cmFsIiwgIlVyYmFuIHdpdGggU2lnbmlmaWNhbnQgUnVyYWwiLCAiVXJiYW4gd2l0aCBDaXR5IGFuZCBUb3duIiwgIlVyYmFuIHdpdGggTWlub3IgQ29udXJiYXRpb24iLCAiVXJiYW4gd2l0aCBNYWpvciBDb251cmJhdGlvbiIpDQoNCm92ZXJhbGxfZGF0YSA8LSBFbmdfZGFpbHlfY292aWQxOV9pbmRpY2F0b3JzICU+JQ0KICBsZWZ0X2pvaW4odXRsYV9kYXRhKSAlPiUNCiAgZ3JvdXBfYnkoZGV0YWlsZWRSdXJhbENsYXNzaWZpY2F0aW9uKSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsQ2FzZXMgPSBzdW0obmV3Q2FzZXNCeVB1Ymxpc2hEYXRlKSwNCiAgICAgICAgICAgIFRvdGFsRGVhdGhzID0gc3VtKG5ld09uc0RlYXRoc0J5UmVnaXN0cmF0aW9uRGF0ZSksDQogICAgICAgICAgICBuTEFEID0gbl9kaXN0aW5jdChhcmVhQ29kZSkpICU+JQ0KICBtdXRhdGUoZGV0YWlsZWRSdXJhbENsYXNzaWZpY2F0aW9uID0gZmFjdG9yKGRldGFpbGVkUnVyYWxDbGFzc2lmaWNhdGlvbiwgZGV0YWlsZWRfcnVjX29yZGVyKSkgJT4lDQogIGFycmFuZ2UoZGV0YWlsZWRSdXJhbENsYXNzaWZpY2F0aW9uKSAlPiUNCiAgbGVmdF9qb2luKHV0bGFfZGF0YSAlPiUgDQogICAgICAgICAgICAgIGdyb3VwX2J5KGRldGFpbGVkUnVyYWxDbGFzc2lmaWNhdGlvbikgJT4lDQogICAgICAgICAgICAgIHN1bW1hcmlzZShwb3AyMDIwID0gc3VtKHBvcHVsYXRpb25NaWQyMDIwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5MQURjaGVjayA9IG5fZGlzdGluY3QoYXJlYUNvZGUpKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKE92ZXJhbGxDYXNlUmF0ZSA9IFRvdGFsQ2FzZXMvcG9wMjAyMCoxMDAwMDAsDQogICAgICAgICBPdmVyYWxsRGVhdGhSYXRlID0gVG90YWxEZWF0aHMvcG9wMjAyMCoxMDAwMDApDQogIA0KIyBvdmVyYWxsX2RhdGEgJT4lDQojICAgZ2dwbG90KGFlcyhPdmVyYWxsQ2FzZVJhdGUsIGRldGFpbGVkUnVyYWxDbGFzc2lmaWNhdGlvbikpICsNCiMgICBnZW9tX2NvbCgpIA0KDQpgYGANCg0KQSBjbGVhciBwYXR0ZXJuIGluIHRoZSBvdmVyYWxsIHJhdGVzIG9mIGNvdmlkIGNhc2VzIHdoZW4gZWFjaCBsb2NhbCBhdXRob3JpdHkgaXMgYWdncmVnYXRlZCBieSBydXJhbCBjbGFzc2lmaWNhdGlvbi4gDQoNClRoZSBvdmVyYWxsIGNhc2UgcmF0ZSBmb3IgdGhlIG1vc3QgcnVyYWwgYXJlYXMgaXMgYHIgcm91bmQob3ZlcmFsbF9kYXRhJE92ZXJhbGxDYXNlUmF0ZVsxXSwwKWAgY2FzZXMgcGVyIDEwMCwwMDAgcG9wdWxhdGlvbiwgd2hpbGUgdGhlIG92ZXJhbGwgY2FzZSByYXRlIGZvciB0aGUgbW9zdCB1cmJhbiBhcmVhcyBpcyBgciByb3VuZChvdmVyYWxsX2RhdGEkT3ZlcmFsbENhc2VSYXRlWzZdLDApYCBjYXNlcyBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uLiANCg0KVGhlIGNvdmlkIHJhdGUgb2YgdGhlIG1vc3QgdXJiYW4gYXJlYXMgaXMgYHIgcm91bmQob3ZlcmFsbF9kYXRhJE92ZXJhbGxDYXNlUmF0ZVs2XS9vdmVyYWxsX2RhdGEkT3ZlcmFsbENhc2VSYXRlWzFdLDEpYCB0aW1lcyB0aGUgY292aWQgcmF0ZSBpbiB0aGUgbW9zdCBydXJhbCBhcmVhcy4NCg0KSG93ZXZlciwgdGhlIG92ZXJhbGwgZGVhdGggcmF0ZSBoYWQgbGVzcyBjbGVhciBwYXR0ZXJuLiBUaGUgbW9zdCBydXJhbCBhcmVhcyBoYWQgdGhlIGEgcmF0ZSBvZiBgciByb3VuZChvdmVyYWxsX2RhdGEkT3ZlcmFsbERlYXRoUmF0ZVsxXSwwKWAgZGVhdGhzIHJlZ2lzdGVyZWQgcGVyIDEwMCwwMDAgcG9wdWxhdGlvbiwgd2hpbGUgdGhlIG92ZXJhbGwgZGVhdGggcmF0ZSBmb3IgdGhlIG1vc3QgdXJiYW4gYXJlYXMgaGFkIHRoZSAzcmQgaGlnaGVzdCBkZWF0aCByYXRlIG9mIGByIHJvdW5kKG92ZXJhbGxfZGF0YSRPdmVyYWxsRGVhdGhSYXRlWzZdLDApYCBkZWF0aHMgcmVnaXN0ZXJlZCBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uLiBUaGUgaGlnaGVzdCBkZWF0aCByYXRlIGNhbWUgZnJvbSBVcmJhbiBhcmVhcyB3aXRoIE1pbm9yIENvbnVyYmF0aW9ucyB3aXRoIGEgZGVhdGggcmF0ZSBvZiBgciByb3VuZChvdmVyYWxsX2RhdGEkT3ZlcmFsbERlYXRoUmF0ZVs1XSwwKWAgZGVhdGhzIHJlZ2lzdGVyZWQgcGVyIDEwMCwwMDAgcG9wdWxhdGlvbi4NCg0KYGBge3IgbWFwcGluZ30NCg0KVVRMQV9zaHAgPC0gc3RfcmVhZCgic3BhdGlhbCBkYXRhL0NPdW50aWVzX2FuZF9Vbml0YXJ5X0F1dGhvcml0aWVzXyhEZWNlbWJlcl8yMDE5KV9Cb3VuZGFyaWVzX1VLX0JGQy5zaHAiKSAlPiUNCiAgcm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoKQ0KDQpVVExBX2Nhc2VzX2RlYXRocyA8LSBFbmdfZGFpbHlfY292aWQxOV9pbmRpY2F0b3JzICU+JQ0KICBncm91cF9ieShhcmVhQ29kZSwgYXJlYU5hbWUpICU+JQ0KICBzdW1tYXJpc2UoVG90YWxDYXNlcyA9IHN1bShuZXdDYXNlc0J5UHVibGlzaERhdGUpLA0KICAgICAgICAgICAgVG90YWxEZWF0aHMgPSBzdW0obmV3T25zRGVhdGhzQnlSZWdpc3RyYXRpb25EYXRlKSwNCiAgICAgICAgICAgIG5MQUQgPSBuX2Rpc3RpbmN0KGFyZWFDb2RlKSkgJT4lDQogIGxlZnRfam9pbih1dGxhX2RhdGEpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIG11dGF0ZShPdmVyYWxsQ2FzZVJhdGUgPSBUb3RhbENhc2VzL3BvcHVsYXRpb25NaWQyMDIwKjEwMDAwMCwNCiAgICAgICAgIE92ZXJhbGxEZWF0aFJhdGUgPSBUb3RhbERlYXRocy9wb3B1bGF0aW9uTWlkMjAyMCoxMDAwMDApDQoNClVUTEFfcnVjX3NocCA8LSBsZWZ0X2pvaW4oVVRMQV9zaHAsIFVUTEFfY2FzZXNfZGVhdGhzLCBieSA9IGMoImN0eXVhMTljZCIgPSAiYXJlYUNvZGUiKSkgJT4lDQogIHN0X3RyYW5zZm9ybSg0MzI2KSAlPiUgIyBDb252ZXJ0IGZyb20gYSBVSyBQcm9qZWN0aW9uIChlcHNnID0gMjc3MDApIHRvIGEgR2xvYmFsIFByb2plY3Rpb24gKGVwc2cgPSA0MzI2KQ0KICBtdXRhdGUoT3ZlcmFsbENhc2VSYXRlX2NvbW1hID0gc2NhbGVzOjpjb21tYShPdmVyYWxsQ2FzZVJhdGUsIGFjY3VyYWN5ID0gMSksDQogICAgICAgICBPdmVyYWxsRGVhdGhSYXRlX2NvbW1hID0gc2NhbGVzOjpjb21tYShPdmVyYWxsRGVhdGhSYXRlLCBhY2N1cmFjeSA9IDEpKQ0KICAjIHNlbGVjdChsYWQxMWNkLCBsYWQxMW5tLCBydWMxMSwgYnJvYWRfcnVjMTEsIHN0X2FyZWFzaGEpDQpgYGANCg0KDQpgYGB7cn0NCmJpbnMgPC0gYygwLCAxMDAwLCAyMDAwLCA0MDAwLCA2MDAwLCA4MDAwLCAxMDAwMCwgSW5mKQ0KcGFsIDwtIGNvbG9yQmluKCJZbE9yUmQiLCBkb21haW4gPSBVVExBX3J1Y19zaHAkT3ZlcmFsbENhc2VSYXRlLCBiaW5zID0gYmlucykNCg0KbGFiZWxzIDwtIHNwcmludGYoDQogICI8c3Ryb25nPiVzPC9zdHJvbmc+PGJyLz4lczxzdHJvbmc+PGJyLz4lcyIsDQogIFVUTEFfcnVjX3NocCRhcmVhTmFtZSwgVVRMQV9ydWNfc2hwJE92ZXJhbGxDYXNlUmF0ZV9jb21tYSwgVVRMQV9ydWNfc2hwJGRldGFpbGVkUnVyYWxDbGFzc2lmaWNhdGlvbg0KKSAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCg0KVVRMQV9ydWNfc2hwICU+JQ0KICBsZWFmbGV0KCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZFBvbHlnb25zKA0KICAgIHN0cm9rZSA9IFQsIA0KICAgIHNtb290aEZhY3RvciA9IDEsIA0KICAgIGZpbGxPcGFjaXR5ID0gMC43LA0KICAgIGZpbGxDb2xvciA9IH5wYWwoT3ZlcmFsbENhc2VSYXRlKSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgd2VpZ2h0ID0gMiwNCiAgICBkYXNoQXJyYXkgPSAiMSIsDQogICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygNCiAgICAgIHdlaWdodCA9IDUsDQogICAgICBjb2xvciA9ICIjNjY2IiwNCiAgICAgIGRhc2hBcnJheSA9ICIiLA0KICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgbGFiZWwgPSBsYWJlbHMsDQogIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygNCiAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwNCiAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICBkaXJlY3Rpb24gPSAiYXV0byIpKQ0KYGBgDQoNCmBgYHtyfQ0KYmlucyA8LSBjKDAsIDUwLCAxMDAsIDE1MCwgMjAwLCAyNTAsIDMwMCwgSW5mKQ0KcGFsIDwtIGNvbG9yQmluKCJZbE9yUmQiLCBkb21haW4gPSBVVExBX3J1Y19zaHAkT3ZlcmFsbERlYXRoUmF0ZSwgYmlucyA9IGJpbnMpDQoNCmxhYmVscyA8LSBzcHJpbnRmKA0KICAiPHN0cm9uZz4lczwvc3Ryb25nPjxici8+JXM8c3Ryb25nPjxici8+JXMiLA0KICBVVExBX3J1Y19zaHAkYXJlYU5hbWUsIFVUTEFfcnVjX3NocCRPdmVyYWxsRGVhdGhSYXRlX2NvbW1hLCBVVExBX3J1Y19zaHAkZGV0YWlsZWRSdXJhbENsYXNzaWZpY2F0aW9uDQopICU+JSBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KDQpVVExBX3J1Y19zaHAgJT4lDQogIGxlYWZsZXQoKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkUG9seWdvbnMoDQogICAgc3Ryb2tlID0gVCwgDQogICAgc21vb3RoRmFjdG9yID0gMSwgDQogICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgZmlsbENvbG9yID0gfnBhbChPdmVyYWxsRGVhdGhSYXRlKSwNCiAgICBjb2xvciA9ICJ3aGl0ZSIsDQogICAgd2VpZ2h0ID0gMiwNCiAgICBkYXNoQXJyYXkgPSAiMSIsDQogICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygNCiAgICAgIHdlaWdodCA9IDUsDQogICAgICBjb2xvciA9ICIjNjY2IiwNCiAgICAgIGRhc2hBcnJheSA9ICIiLA0KICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsDQogICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgbGFiZWwgPSBsYWJlbHMsDQogIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucygNCiAgICBzdHlsZSA9IGxpc3QoImZvbnQtd2VpZ2h0IiA9ICJub3JtYWwiLCBwYWRkaW5nID0gIjNweCA4cHgiKSwNCiAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwNCiAgICBkaXJlY3Rpb24gPSAiYXV0byIpKQ0KYGBgDQoNCg==